
package kvsnode;

import java.rmi.AccessException;
import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * An RMI registry that can be used by remote Java VMs, but requires
 * bootstrapping by being looked up from a "real" RMI registry.
 * 
 * @author Daniel M. Zimmerman
 * @version May 2013
 */
public class RemoteRegistry implements Registry
{
  /**
   * The default proxy registry name.
   */
  public static final String DEFAULT_NAME = "RemoteRegistry";
  
  /**
   * The minimum TCP port on which to create a registry.
   */
  public static final int MIN_PORT = 1025;
  
  /**
   * The maximum TCP port on which to create a registry.
   */
  public static final int MAX_PORT = 65535;
  
  /**
   * The Map in which to store the bindings.
   */
  private final Map<String, Remote> my_bindings;

  /**
   * Constructs a new ProxyRegistry object for the specified RMI
   * registry.
   */
  public RemoteRegistry()
  {
    my_bindings = Collections.synchronizedMap(new HashMap<String, Remote>());
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  public Remote lookup(final String the_name) 
    throws RemoteException, NotBoundException, AccessException
  {
    return my_bindings.get(the_name);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void bind(final String the_name, final Remote the_object) 
    throws RemoteException, AlreadyBoundException, AccessException
  {
    synchronized (my_bindings)
    {
      if (my_bindings.get(the_name) != null)
      {
        throw new AlreadyBoundException(the_name + " is already bound to " + 
                                        my_bindings.get(the_name));
      }
      my_bindings.put(the_name, the_object);
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void unbind(final String the_name) 
    throws RemoteException, NotBoundException, AccessException
  {
    synchronized (my_bindings)
    {
      if (my_bindings.get(the_name) == null)
      {
        throw new NotBoundException(the_name + " is not bound");
      }
      my_bindings.remove(the_name);
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void rebind(final String the_name, final Remote the_object) 
    throws RemoteException, AccessException
  {
    my_bindings.put(the_name, the_object);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String[] list() throws RemoteException, AccessException
  {
    synchronized (my_bindings)
    {
      return my_bindings.keySet().toArray(new String[0]); 
    }
  }
}
